"""
Unit tests for MonitoringService
"""
import pytest
from datetime import datetime, timedelta
from services.monitoring_service import MonitoringService
from models.workflow import Workflow
from models.workflow_instance import WorkflowInstance
import json


class TestMonitoringService:
    """Test MonitoringService methods"""

    def _create_test_workflow(self, db_session, name="测试工作流"):
        """Helper to create a test workflow"""
        workflow = Workflow(
            name=name,
            description="测试工作流",
            workflow_definition=json.dumps({"nodes": []}),
            status="草稿",
            created_by="test_user"
        )
        db_session.add(workflow)
        db_session.commit()
        db_session.refresh(workflow)
        return workflow

    def _create_test_instance(
        self,
        db_session,
        workflow_id,
        status="已完成",
        finished_at=None,
        duration=None
    ):
        """Helper to create a test workflow instance"""
        instance = WorkflowInstance(
            workflow_id=workflow_id,
            instance_name=f"测试实例_{status}",
            status=status,
            trigger_type="manual",
            finished_at=finished_at,
            duration=duration
        )
        db_session.add(instance)
        db_session.commit()
        db_session.refresh(instance)
        return instance

    def test_get_statistics_basic(self, db_session):
        """Test getting basic statistics"""
        workflow = self._create_test_workflow(db_session)

        # Create instances with different statuses
        now = datetime.now()
        self._create_test_instance(db_session, workflow.id, "运行中")
        self._create_test_instance(db_session, workflow.id, "等待中")
        self._create_test_instance(
            db_session, workflow.id, "已完成",
            finished_at=now, duration=100
        )
        self._create_test_instance(
            db_session, workflow.id, "失败",
            finished_at=now, duration=50
        )

        stats = MonitoringService.get_statistics(db_session, days=7)

        assert stats["running_workflows"] == 2  # 运行中 + 等待中
        assert stats["today_success"] == 1
        assert stats["today_failed"] == 1
        assert stats["success_rate"] == 0.5  # 1 success out of 2 completed
        assert len(stats["trend"]) == 7

    def test_get_statistics_success_rate(self, db_session):
        """Test success rate calculation"""
        workflow = self._create_test_workflow(db_session)
        now = datetime.now()

        # Create 7 successful and 3 failed instances
        for _ in range(7):
            self._create_test_instance(
                db_session, workflow.id, "已完成",
                finished_at=now, duration=100
            )

        for _ in range(3):
            self._create_test_instance(
                db_session, workflow.id, "失败",
                finished_at=now, duration=50
            )

        stats = MonitoringService.get_statistics(db_session)

        # Success rate should be 70% (7 out of 10)
        assert stats["success_rate"] == 0.7

    def test_get_statistics_trend(self, db_session):
        """Test trend data generation"""
        workflow = self._create_test_workflow(db_session)
        now = datetime.now()

        # Create instances for the last 3 days
        for i in range(3):
            date = now - timedelta(days=i)
            # 2 successful instances per day
            for _ in range(2):
                self._create_test_instance(
                    db_session, workflow.id, "已完成",
                    finished_at=date, duration=100
                )
            # 1 failed instance per day
            self._create_test_instance(
                db_session, workflow.id, "失败",
                finished_at=date, duration=50
            )

        stats = MonitoringService.get_statistics(db_session, days=7)

        trend = stats["trend"]
        assert len(trend) == 7

        # Check the recent 3 days have data
        for i in range(3):
            day_data = trend[-(i+1)]  # Last 3 days
            assert day_data["success"] >= 2
            assert day_data["failed"] >= 1

    def test_get_recent_instances(self, db_session):
        """Test getting recent instances"""
        workflow = self._create_test_workflow(db_session)

        # Create 15 instances
        for i in range(15):
            self._create_test_instance(db_session, workflow.id, "已完成")

        # Get recent 10
        instances = MonitoringService.get_recent_instances(db_session, limit=10)

        assert len(instances) == 10

        # Get recent 20 (should return all 15)
        instances = MonitoringService.get_recent_instances(db_session, limit=20)

        assert len(instances) == 15

    def test_get_recent_instances_with_status_filter(self, db_session):
        """Test getting recent instances with status filter"""
        workflow = self._create_test_workflow(db_session)

        # Create instances with different statuses
        for _ in range(5):
            self._create_test_instance(db_session, workflow.id, "已完成")
        for _ in range(3):
            self._create_test_instance(db_session, workflow.id, "失败")
        for _ in range(2):
            self._create_test_instance(db_session, workflow.id, "运行中")

        # Filter by status
        completed = MonitoringService.get_recent_instances(
            db_session, limit=20, status="已完成"
        )
        assert len(completed) == 5

        failed = MonitoringService.get_recent_instances(
            db_session, limit=20, status="失败"
        )
        assert len(failed) == 3

        running = MonitoringService.get_recent_instances(
            db_session, limit=20, status="运行中"
        )
        assert len(running) == 2

    def test_get_workflow_status_distribution(self, db_session):
        """Test status distribution"""
        workflow = self._create_test_workflow(db_session)

        # Create instances with various statuses
        statuses = {
            "已完成": 10,
            "失败": 5,
            "运行中": 3,
            "等待中": 2,
            "已取消": 1
        }

        for status, count in statuses.items():
            for _ in range(count):
                self._create_test_instance(db_session, workflow.id, status)

        distribution = MonitoringService.get_workflow_status_distribution(db_session)

        assert distribution["已完成"] == 10
        assert distribution["失败"] == 5
        assert distribution["运行中"] == 3
        assert distribution["等待中"] == 2
        assert distribution["已取消"] == 1

    def test_get_average_duration(self, db_session):
        """Test average duration calculation"""
        workflow = self._create_test_workflow(db_session)
        now = datetime.now()

        # Create instances with different durations
        durations = [100, 200, 300, 150, 250]
        for duration in durations:
            self._create_test_instance(
                db_session, workflow.id, "已完成",
                finished_at=now, duration=duration
            )

        stats = MonitoringService.get_average_duration(db_session)

        assert stats["total_count"] == 5
        assert stats["average_duration"] == 200.0  # (100+200+300+150+250)/5
        assert stats["min_duration"] == 100
        assert stats["max_duration"] == 300

    def test_get_average_duration_no_data(self, db_session):
        """Test average duration with no completed instances"""
        stats = MonitoringService.get_average_duration(db_session)

        assert stats["total_count"] == 0
        assert stats["average_duration"] == 0
        assert stats["min_duration"] == 0
        assert stats["max_duration"] == 0

    def test_get_top_workflows(self, db_session):
        """Test getting top workflows"""
        # Create multiple workflows
        workflow1 = self._create_test_workflow(db_session, "工作流1")
        workflow2 = self._create_test_workflow(db_session, "工作流2")
        workflow3 = self._create_test_workflow(db_session, "工作流3")

        now = datetime.now()

        # Workflow 1: 10 executions (8 success, 2 failures)
        for _ in range(8):
            self._create_test_instance(
                db_session, workflow1.id, "已完成",
                finished_at=now, duration=100
            )
        for _ in range(2):
            self._create_test_instance(
                db_session, workflow1.id, "失败",
                finished_at=now, duration=50
            )

        # Workflow 2: 5 executions (all success)
        for _ in range(5):
            self._create_test_instance(
                db_session, workflow2.id, "已完成",
                finished_at=now, duration=100
            )

        # Workflow 3: 3 executions (1 success, 2 failures)
        self._create_test_instance(
            db_session, workflow3.id, "已完成",
            finished_at=now, duration=100
        )
        for _ in range(2):
            self._create_test_instance(
                db_session, workflow3.id, "失败",
                finished_at=now, duration=50
            )

        top_workflows = MonitoringService.get_top_workflows(db_session, limit=10)

        # Should be ordered by execution count
        assert len(top_workflows) == 3
        assert top_workflows[0]["workflow_id"] == workflow1.id
        assert top_workflows[0]["execution_count"] == 10
        assert top_workflows[0]["success_rate"] == 0.8

        assert top_workflows[1]["workflow_id"] == workflow2.id
        assert top_workflows[1]["execution_count"] == 5
        assert top_workflows[1]["success_rate"] == 1.0

        assert top_workflows[2]["workflow_id"] == workflow3.id
        assert top_workflows[2]["execution_count"] == 3
        assert top_workflows[2]["success_rate"] == round(1/3, 4)

    def test_get_top_workflows_with_limit(self, db_session):
        """Test top workflows with limit"""
        # Create 5 workflows with different execution counts
        for i in range(5):
            workflow = self._create_test_workflow(db_session, f"工作流{i}")
            # Create (5-i) executions for each
            for _ in range(5 - i):
                self._create_test_instance(db_session, workflow.id, "已完成")

        # Get top 3
        top_workflows = MonitoringService.get_top_workflows(db_session, limit=3)

        assert len(top_workflows) == 3
        # Should be ordered by execution count descending
        assert top_workflows[0]["execution_count"] == 5
        assert top_workflows[1]["execution_count"] == 4
        assert top_workflows[2]["execution_count"] == 3
